package com.Xht.www.config;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class CustomDatabaseConnectionPool {

    // 连接池和使用中的连接列表
    private List<Connection> connectionPool;
    private List<Connection> usedConnections;

    // 每个连接的最后访问时间记录
    private Map<Connection, Long> lastAccessTimeMap;

    // 数据库配置参数
    private final String url;
    private final String user;
    private final String password;
    private final int initialPoolSize;
    private final int minPoolSize;
    private int maxPoolSize;
    private final long waitTimeout;
    private final long idleTimeout;
    // 数据库配置参数（新增扩容相关）
    private final int maxHardLimit;        // 最大连接数硬限制
    private final int autoExpandStep;     // 每次自动扩容的连接数
    private final long expandCheckInterval; // 扩容检查间隔（毫秒）


    // 定时任务调度器
    private final ScheduledExecutorService scheduler;

    // 单例实例
    private static CustomDatabaseConnectionPool instance;

    // 私有构造函数，防止外部直接创建
    private CustomDatabaseConnectionPool(String url, String user, String password,
                                         int initialPoolSize, int minPoolSize,
                                         int maxPoolSize, long waitTimeout, long idleTimeout,
                                         int maxHardLimit, int autoExpandStep, long expandCheckInterval) {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            System.out.println("JDBC 驱动加载成功");
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("JDBC Driver not found", e);
        }

        this.url = url;
        this.user = user;
        this.password = password;
        this.initialPoolSize = initialPoolSize;
        this.minPoolSize = minPoolSize;
        this.maxPoolSize = maxPoolSize;
        this.waitTimeout = waitTimeout;
        this.idleTimeout = idleTimeout;
        this.maxHardLimit = maxHardLimit;
        this.autoExpandStep = autoExpandStep;
        this.expandCheckInterval = expandCheckInterval;

        this.connectionPool = new ArrayList<>();
        this.usedConnections = new ArrayList<>();
        this.lastAccessTimeMap = new HashMap<>();
        this.scheduler = Executors.newScheduledThreadPool(1);

        initializePool();
        scheduleIdleConnectionCheck();
        scheduleAutoExpand(); // 启动扩容任务
    }

    //连接池基本配置
    public static synchronized CustomDatabaseConnectionPool getInstance() {
        if (instance == null) {
            String dbUrl = "jdbc:mysql://localhost:3306/hotelmanagementdb";
            String dbUser = "xie";
            String dbPassword = "123456";
            int initialPoolSize = 30;
            int minPoolSize = 5;
            int maxPoolSize = 100;
            long waitTimeout = 10000;
            long idleTimeout = 60000;
            int maxHardLimit = 50;      // 最大连接硬限制
            int autoExpandStep = 5;     // 每次扩容增加5个连接
            long expandCheckInterval = 30000; // 每30秒检查是否需要扩容

            instance = new CustomDatabaseConnectionPool(dbUrl, dbUser, dbPassword,
                    initialPoolSize, minPoolSize, maxPoolSize, waitTimeout, idleTimeout,
                    maxHardLimit, autoExpandStep, expandCheckInterval);
        }
        return instance;
    }


    // 初始化连接池
    private void initializePool() {
        try {
            for (int i = 0; i < initialPoolSize; i++) {
                Connection conn = DriverManager.getConnection(url, user, password);
                if (isConnectionValid(conn)) { // 确保初始连接有效
                    connectionPool.add(conn);
                    lastAccessTimeMap.put(conn, System.currentTimeMillis());
                } else {
                    System.err.println("Failed to create valid initial connection");
                    // 关闭无效连接
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
            // 打印初始化后的连接池大小，便于调试
            System.out.println("Initialized connection pool with size: " + connectionPool.size());
        } catch (SQLException e) {
            System.err.println("Failed to initialize connection pool: " + e.getMessage());
            e.printStackTrace();
        }
    }

    //数据库连接池自动扩容
    private void scheduleAutoExpand() {
        scheduler.scheduleAtFixedRate(() -> {
            synchronized (this) {
                int totalConnections = connectionPool.size() + usedConnections.size();

                if (totalConnections >= maxPoolSize && maxPoolSize < maxHardLimit) {
                    int newConnections = Math.min(autoExpandStep, maxHardLimit - maxPoolSize);
                    System.out.println("🔌 自动扩容中，尝试增加 " + newConnections + " 个连接");

                    for (int i = 0; i < newConnections; i++) {
                        try {
                            Connection conn = DriverManager.getConnection(url, user, password);
                            if (isConnectionValid(conn)) {
                                connectionPool.add(conn);
                                lastAccessTimeMap.put(conn, System.currentTimeMillis());
                            } else {
                                conn.close();
                            }
                        } catch (SQLException ignored) {}
                    }

                    maxPoolSize += newConnections;
                    System.out.println("当前最大连接数已提升至：" + maxPoolSize);
                }
            }
        }, expandCheckInterval, expandCheckInterval, TimeUnit.MILLISECONDS);
    }



    // 获取一个可用连接
    public synchronized Connection getConnection() {
        long startTime = System.currentTimeMillis();

        // 如果当前没有可用连接且未达最大连接数，则创建新连接
        while (true) {
            if (!connectionPool.isEmpty()) {
                Connection conn = connectionPool.remove(0);
                if (isConnectionValid(conn)) {
                    usedConnections.add(conn);
                    long currentTime = System.currentTimeMillis();
                    lastAccessTimeMap.put(conn, currentTime);
                    return conn;
                } else {
                    // 连接无效则关闭并继续尝试获取
                    try {
                        conn.close();
                    } catch (SQLException ignored) {}
                }
            }

            // 当前连接池不足，尝试新建连接
            if (connectionPool.size() + usedConnections.size() < maxPoolSize) {
                try {
                    Connection newConn = DriverManager.getConnection(url, user, password);
                    if (isConnectionValid(newConn)) {
                        connectionPool.add(newConn);
                        lastAccessTimeMap.put(newConn, System.currentTimeMillis());
                        continue; // 创建成功后重新尝试获取
                    } else {
                        System.err.println("Failed to create valid connection");
                        try {
                            newConn.close();
                        } catch (SQLException ignored) {}
                    }
                } catch (SQLException e) {
                    throw new RuntimeException("Error creating database connection", e);
                }
            }

            // 等待直到有连接被释放
            long elapsedTime = System.currentTimeMillis() - startTime;
            if (elapsedTime >= waitTimeout) {
                throw new RuntimeException("Timeout waiting for a database connection");
            }

            try {
                wait(waitTimeout - elapsedTime);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("Interrupted while waiting for connection", e);
            }
        }
    }

    // 检查连接是否有效
    private boolean isConnectionValid(Connection conn) {
        try {
            return conn != null && !conn.isClosed() && conn.isValid(5);
        } catch (SQLException e) {
            return false;
        }
    }

    // 释放连接回池
    public synchronized void releaseConnection(Connection conn) {
        if (conn != null) {
            usedConnections.remove(conn);
            if (isConnectionValid(conn)) {
                connectionPool.add(conn);
                lastAccessTimeMap.put(conn, System.currentTimeMillis());
            } else {
                try {
                    conn.close();
                } catch (SQLException ignored) {}
            }
            notifyAll();
        }
    }

    // 关闭连接池
    public void closePool() {
        scheduler.shutdown();
        for (Connection conn : connectionPool) {
            try {
                conn.close();
            } catch (SQLException ignored) {}
        }
        for (Connection conn : usedConnections) {
            try {
                conn.close();
            } catch (SQLException ignored) {}
        }
        connectionPool.clear();
        usedConnections.clear();
        lastAccessTimeMap.clear();
    }

    // 定期清理空闲连接
    private void scheduleIdleConnectionCheck() {
        scheduler.scheduleAtFixedRate(() -> {
            synchronized (this) {
                long now = System.currentTimeMillis();
                List<Connection> toRemove = new ArrayList<>();

                for (Connection conn : connectionPool) {
                    Long accessTime = lastAccessTimeMap.get(conn);
                    if (accessTime != null && now - accessTime > idleTimeout) {
                        toRemove.add(conn);
                    }
                }

                for (Connection conn : toRemove) {
                    connectionPool.remove(conn);
                    lastAccessTimeMap.remove(conn);
                    try {
                        conn.close();
                    } catch (SQLException ignored) {}
                }

                // 确保不低于最小连接数
                while (connectionPool.size() < minPoolSize && connectionPool.size() < maxPoolSize) {
                    try {
                        Connection newConn = DriverManager.getConnection(url, user, password);
                        if (isConnectionValid(newConn)) { // 确保新连接有效
                            connectionPool.add(newConn);
                            lastAccessTimeMap.put(newConn, System.currentTimeMillis());
                        } else {
                            System.err.println("Failed to create valid connection during idle check");
                        }
                    } catch (SQLException ignored) {}
                }

            }
        }, idleTimeout, idleTimeout, TimeUnit.MILLISECONDS);
    }
}


